#!/bin/python

import os
import json
import sys
import re

from fnmatch import fnmatch, fnmatchcase

config_json = "kconfig.json"
config_script = "config_script.py"

compare_all_flag = False

feature = []
diff_bad_config = []
feature2 = []
different = []
same = []
good_config = []
bad_config = []

def draw_all_node(config_list, dir):
    select_node = []
    depend_node = []
    for config_item in config_list:
        print(config_item.get("Name"))
        selects = _config_selects(config_item)
        if selects != "":
            for select in selects:
                config = name_to_node(select, config_list)
                select_node.append(config_list)
                config_item["SELECT"] = select_node
        depends = _config_depends(config_item)
        if depends != "":
            for depend in depends:
                config = name_to_node(depend, config_list)
                depend_node.append(config_list)
                config_item["DEPEND"] = depend_node
        print("==================================================================================================================")
        print(config_item)

def base_info(dir, file):
    print("获取{}配置信息。。。".format(dir))
    command = "make -C " + dir + " scriptconfig SCRIPT=" + config_script
    os.system(command)
    print("读取{}配置信息。。。".format(file))
    f = open(file, "r")
    content = f.read()
    config = json.loads(content)
    print("处理反向依赖关系")
    re_depend(config)
    print("处理反向选择关系")
    re_select(config)
    #print("统计信息中")
    #count_level(config, dir)
    # 循环，json无法处理，print(DEFCONFIG_LIST)6786193个字符
    #print("添加节点关系")
    #draw_all_node(config, dir)
    print("--version: {}".format(config[0].get("Name")))
    print("--config count: {}".format(len(config)))
    write_data(config, dir + "-kconfig")
    return config


def diff_same_config(config_value, list1, number1, list2, number2):
    Str_value1 = "no"
    Str_value2 = "ok"
    same_flag = 1
    dict = {}
    dict["Name"] = config_value
    if list1[number1].get("Config_value") != list2[number2].get("Config_value"):
        if list1[number1].get("Config_value") == "m" or list1[number1].get("Config_value") == "y":
            Str_value1 = "y"
        if list2[number2].get("Config_value") == "m" or list2[number2].get("Config_value") == "y":
            Str_value2 = "y"
        same_flag = 0
        if Str_value1 == Str_value2:
            same_flag = 1
        dict["Config_string1"] = list1[number1].get("Config_string")
        dict["Config_string2"] = list2[number2].get("Config_string")
        if list1[number1].get("Depends") != list2[number2].get("Depends"):
            dict["Depends1"] = list1[number1].get("Depends")
            dict["Depends2"] = list2[number2].get("Depends")
    if same_flag == 1:
        same.append(list1[number1])
    else:
        different.append(dict)
    if list1[number1] != list2[number2]:
        diff_bad_config.append(list2[number2])

def match_str(target, source, flag):
    if flag == 0:
        source_str = source
    elif flag == 1:
        source_str = source + "*"
    else:
        source_str = "*" + source + "*"

    return fnmatch(target, source_str)


def search_same_config(config_item, lists):
    number = 0
    for temp_item in lists:
        config_value = config_item.get("Name")
        temp_value = temp_item.get("Name")
        if temp_value == config_value and config_item.get(
            "Menu_path_info"
        ) == temp_item.get("Menu_path_info"):
            return number
        number += 1
    return -1


def compare(list1, list2, string):
    global compare_all_flag
    number1 = 0
    match_flag = True
    for config_item in list1:
        config_value = config_item.get("Name")
        config_local = config_item.get("Local")

        if string != "":
            compare_all_flag = False
            match_flag = match_str(config_local, string, 1)
        else:
            compare_all_flag = True
        if match_flag is False:
            number1 += 1
            continue

        same_flag = search_same_config(config_item, list2)
        if same_flag >= 0:
            diff_same_config(config_value, list1, number1, list2, same_flag)

        if same_flag == -1:
            feature.append(config_item)
        number1 += 1


def get_list2_feature(list1, list2, string):
    flag = True
    for temp_item in list2:
        temp_local = temp_item.get("Local")
        if string != "":
            flag = match_str(temp_local, string, 1)
        else:
            flag = True
        if flag is True:
            if temp_item not in list1 and temp_item not in diff_bad_config:
                feature2.append(temp_item)

def count_level(configs, filename):
    for flag in [1, 2, 3]:
        # 文件存在配置项的数量
        if flag == 1:
            str_flag = "Local"
            count_dict = {}
        # 文件的source的配置项数量
        if flag == 2:
            str_flag = "Iinclude_path_info"
            count_dict = {}
        # 菜单下的配置项数量
        if flag == 3:
            str_flag = "Menu_path_info"
            count_dict = {}
        for config_item in configs:
            config_str = config_item.get(str_flag)
            count = count_dict.get(config_str, 0)
            if count == 0:
                count_dict[config_str] = 1
            else:
                count += 1
                count_dict[config_str] = count
        filename = filename + "-" + str_flag
        write_data(count_dict, filename)


def write_data(node_list, filename):
    with open(filename + ".json", "w") as outfile:
        data = json.dump(node_list, outfile, indent=4, separators=(",", ": "))


def compare_choice_dir(good_config, bad_config, choice_dir):
    feature2.clear()
    feature.clear()
    same.clear()
    different.clear()
    diff_bad_config.clear()
    compare(good_config, bad_config, choice_dir)
    get_list2_feature(good_config, bad_config, choice_dir)
    print("不同的配置项数量：{}".format(len(different)))
    print("相同的配置项数量：{}".format(len(same)))
    print("{} 独有的配置项数量：{}".format(sys.argv[1], len(feature)))
    print("{} 独有的配置项数量：{}".format(sys.argv[2], len(feature2)))
    write_data(same, "same")
    write_data(different, "different")
    write_data(feature, sys.argv[1] + "-feature")
    write_data(feature2, sys.argv[2] + "-feature")


def print_config_name(config_list):
    config_names = []
    for config_item in config_list:
        config_name = config_item.get("Name")
        config_names.append(config_name)
    return config_names


def _config_selects(config_item):
    configRegex = re.compile(r"[A-Z_0-9]{1,}[A-Za-z /-]{0,}")
    selects = "" if configRegex.findall(config_item.get("Select")) == [] else set(configRegex.findall(config_item.get("Select")))
    return selects

def _config_depends(config_item):
    configRegex = re.compile(r"[A-Z_0-9]{1,}[A-Za-z /-]{0,}")
    depends = "" if configRegex.findall(config_item.get("Depends")) == [] else set(configRegex.findall(config_item.get("Depends")))
    return depends

def _print_config(config_item):
    if _config_depends(config_item) != '':
        print("依赖项：{}".format(_config_depends(config_item)))
    else:
        print("无依赖项")
    if _config_selects(config_item) != '':
        print("选择项：{}".format(_config_selects(config_item)))
    else:
        print("无选择项")


def print_config(config_name):
    config_flag = 0
    config_diff = 0
    for config_item in same:
        if fnmatch(config_name, config_item.get("Name")):
            config_flag = 1
            print(json.dumps(config_item, indent=4, separators=(",", ": ")))
            print("配置项 {} 属于相同的配置项".format(config_name))
            _print_config(config_item)
            break
    for config_item in different:
        if fnmatch(config_name, config_item.get("Name")):
            config_flag = 1
            config_diff = 1
            print(json.dumps(config_item, indent=4, separators=(",", ": ")))
            print("配置项 {} 属于配置不同的配置项".format(config_name))
            break
    for config_item in feature:
        if fnmatch(config_name, config_item.get("Name")):
            config_flag = 1
            print(json.dumps(config_item, indent=4, separators=(",", ": ")))
            print("配置项 {} 属于配置1独有的".format(config_name))
            _print_config(config_item)
            break
    for config_item in feature2:
        if fnmatch(config_name, config_item.get("Name")):
            config_flag = 1
            print(json.dumps(config_item, indent=4, separators=(",", ": ")))
            print("配置项 {} 属于配置2独有的".format(config_name))
            _print_config(config_item)
            break
    if config_flag == 0:
        print("配置项 {} 不存在".format(config_name))
        if compare_all_flag == False:
            print("尝试对比所有配置项后重新查看")

    if config_diff == 1:
        for config_item in good_config:
            if fnmatch(config_name, config_item.get("Name")):
                print(json.dumps(config_item, indent=4, separators=(",", ": ")))
                _print_config(config_item)
        for config_item in bad_config:
            if fnmatch(config_name, config_item.get("Name")):
                print(json.dumps(config_item, indent=4, separators=(",", ": ")))
                _print_config(config_item)

def print_help():
    print("h/?            -输出帮助信息")
    print("q              -退出")
    print("compare        -对比指定目录下的配置项")
    print("print          -打印指定的所属列表(same, different, feature, feature2)的配置项名称")
    print("config         -打印指定的配置项信息")
    print("result         -打印结果")

def _re_info(config_value, config_names, config_list, s):
    for config_name in config_names:
        for re_configname in config_list:
            if re_configname.get("Name") == config_name:
                config_values = (
                    []
                    if re_configname.get(s, "") == ""
                    else re_configname.get(s)
                )
                config_values.append(config_value)
                re_configname[s] = config_values
                # break

def re_select(config_list):
    for config_item in config_list:
        config_value = config_item.get("Name")
        selects = _config_selects(config_item)
        _re_info(config_value, selects, config_list, "Re-selects")

def re_depend(config_list):
    for config_item in config_list:
        config_value = config_item.get("Name")
        depends = _config_depends(config_item)
        _re_info(config_value, depends, config_list, "Re-depends")

def all_in_same(config_depends):
    depend_in_same_flag = True
    for config_name in config_depends:
        config = name_to_node(config_name, good_config)
        if config not in same:
            depend_in_same_flag = False
    return depend_in_same_flag

def have_diff(config_selects):
    select_have_diff_flag = False
    for config_name in config_selects:
        config = name_to_node(config_name, good_config)
        if config not in same:
            select_have_diff_flag = True
    return select_have_diff_flag

def print_result():
    result_config = []
    alone_config = []
    depend_flag = False
    select_falg = False
    re_depends_flag = False
    re_selects_flag = False
    depend_zero_flag = False
    select_zero_falg = False
    re_depends_zero_flag = False
    re_selects_zero_flag = False
    for config_name in print_config_name(different):
        config_node = name_to_node(config_name, good_config) # 还有badconfig
        print(config_node.get("Name", ""))
        if len(_config_depends(config_node)) > 0:
            print("依赖：{}".format(_config_depends(config_node)))
            depend_flag = all_in_same(_config_depends(config_node))
        else:
            depend_zero_flag = True
        if len(_config_selects(config_node)) > 0:
            print("选择：{}".format(_config_selects(config_node)))
            select_falg = have_diff(_config_selects(config_node))
        else:
            select_zero_falg = True
        if len(config_node.get("Re-depends", "")) > 0:
            print("被 {} 依赖".format(set(config_node.get("Re-depends", ""))))
            re_depends_flag = have_diff(set(config_node.get("Re-depends", "")))
        else:
            re_depends_zero_flag = True
        if len(config_node.get("Re-selects", "")) > 0:
            print("被 {} 选择".format(set(config_node.get("Re-selects", ""))))
            re_selects_flag = have_diff(set(config_node.get("Re-selects", "")))
        else:
            re_selects_zero_flag = True
        if depend_flag == True and re_selects_flag == False:
            depend_flag = False
            alone_config.append(config_node.get("Name", ""))
        elif select_falg == True or re_depends_flag == True:
            select_falg = False
            re_depends_flag = False
            result_config.append(config_node.get("Name", ""))
    if len(result_config) > 0:
        print("需要处理 {} 项，配置项：{}".format(len(set(result_config)), set(result_config)))
    if len(alone_config) > 0:
        print("单独的 {} 项，配置项：{}".format(len(set(alone_config)), set(alone_config)))

def name_to_node(config_name, config_list):
    for config_item in config_list:
        if fnmatch(config_name, config_item.get("Name")):
            #config_item["Belong"] = "one"
            return config_item

if __name__ == "__main__":

    good_config = base_info(sys.argv[1], sys.argv[1] + "/" + config_json)
    bad_config = base_info(sys.argv[2], sys.argv[2] + "/" + config_json)

    choice_dir = input("输入要对比的目录(直接回车对比全部): ")
    compare_choice_dir(good_config, bad_config, choice_dir)
    print_help()

    while True:
        choice = input(">>> ")
        if choice == "h" or choice == "?":
            print_help()
        if choice == "q":
            break
        if choice == "compare":
            choice_dir = input("输入要对比的目录(直接回车对比全部): ")
            compare_choice_dir(good_config, bad_config, choice_dir)
        if choice == "print":
            result = input("输入要打印的内容(same, different, feature1, feature2): ")
            if result == "same":
                print(print_config_name(same))
            if result == "different":
                print(print_config_name(different))
            if result == "feature1":
                print(print_config_name(feature))
            if result == "feature2":
                print(print_config_name(feature2))
        if choice == "config":
            config_name = input("输入要打印的配置项: ")
            print_config(config_name)
        if choice == "result":
            print_result()
